package com.glsc.ngateway.amdoc.handler;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@ControllerAdvice
public class GlobalExceptionHanler {


    private Logger logger = LoggerFactory.getLogger(this.getClass());


    /**
     * @param exception
     * @param request
     * @param response
     * @return
     * @Description 表单验证异常
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public InterfaceReponse validExceptionHandler(BindException exception, HttpServletRequest request, HttpServletResponse response) {
        exception.printStackTrace();
        List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
        Map<String, String> errors = new HashMap<>();
        for (FieldError error : fieldErrors) {
            errors.put(error.getField(), error.getDefaultMessage());
        }
        logger.error("抛出表单验证异常：" + JSON.toJSONString(errors) + "时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond));
        return InterfaceReponse.returnException(JSON.toJSONString(errors));
    }


    /**
     * @param exception
     * @Description 500异常处理
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public InterfaceReponse errorHandler(Exception exception) {
        exception.printStackTrace();
        logger.error("抛出Exception异常：" + exception.getClass().getSimpleName() + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond));
        return InterfaceReponse.returnError("Exception 异常，异常类为：" + exception.getClass().getSimpleName(), ExceptionConstant.Run500, ExceptionConstant.ERROR);
    }

    /**
     * @param basicException
     * @return
     * @Description 运行时错误异常处理
     */
    @ExceptionHandler(value = BasicException.class)
    @ResponseBody
    public InterfaceReponse basicException(BasicException basicException) {
        basicException.printStackTrace();
        logger.error("抛出BasicException异常：" + basicException + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond));
        return InterfaceReponse.returnError("Runtime Exception 异常，异常类为：" + basicException, ExceptionConstant.RunTime, ExceptionConstant.ERROR);
    }


    /**
     * @param exception
     * @return
     * @Description 业务异常
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public InterfaceReponse businessExceptionHandler(BusinessException exception) {
        logger.error("抛出业务异常：" + exception + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), exception);
        return InterfaceReponse.returnError("业务异常，" + exception.getMessage(), exception.getCode(), ExceptionConstant.EXCEPTION);
    }


    /**
     * @param ex
     * @return
     * @Description 空指针异常。
     */
    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    public InterfaceReponse nullPointerExceptionHandler(NullPointerException ex) {
        logger.error("抛出NullPointerException异常：" + ex + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), ex);
        return InterfaceReponse.returnError("NullPoint 异常，异常类为：" + ex.getClass().getSimpleName(), ExceptionConstant.NullPointer, ExceptionConstant.ERROR);
    }

    //类型转换异常

    /**
     * @param ex
     * @return
     * @Description 类型转换异常
     */
    @ExceptionHandler(value = ClassCastException.class)
    @ResponseBody
    public InterfaceReponse classCastExceptionHandler(ClassCastException ex) {
        logger.error("抛出ClassCastExceptionHandler异常：" + ex + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), ex);
        return InterfaceReponse.returnError("类型转换异常，异常类为：" + ex.getClass().getSimpleName(), ExceptionConstant.ClassCast, ExceptionConstant.ERROR);
    }

    /**
     * @param ex
     * @return
     * @Description IO Exception
     */
    @ExceptionHandler(value = IOException.class)
    @ResponseBody
    public InterfaceReponse iOExceptionHandler(IOException ex) {
        logger.error("抛出IOExceptionHandler异常：" + ex + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), ex);
        return InterfaceReponse.returnError("IOException，异常类为：" + ex.getClass().getSimpleName(), ExceptionConstant.IO, ExceptionConstant.ERROR);
    }


    /**
     * @param ex
     * @return
     * @Description 栈溢出 异常
     */
    @ExceptionHandler(value = StackOverflowError.class)
    @ResponseBody
    public InterfaceReponse stackOverflowErrorHandler(StackOverflowError ex) {
        logger.error("抛出 stackOverflowError异常：" + ex + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), ex);
        return InterfaceReponse.returnError("StackOverflow 异常，异常类为：" + ex.getClass().getSimpleName(), ExceptionConstant.StackOverflow, ExceptionConstant.ERROR);
    }


    /**
     * @param ex
     * @return
     * @Description 未知方法异常
     */
    @ExceptionHandler(value = NoSuchMethodException.class)
    @ResponseBody
    public InterfaceReponse noSuchMethodExceptionHandler(StackOverflowError ex) {
        logger.error("抛出 NoSuchMethodException 异常：" + ex + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), ex);
        return InterfaceReponse.returnError("NoSuchMethodException 异常，异常类为：" + ex.getClass().getSimpleName(), ExceptionConstant.StackOverflow, ExceptionConstant.ERROR);
    }

    /**
     * @param ex
     * @return
     * @Description 数组越界异常
     */
    @ExceptionHandler(IndexOutOfBoundsException.class)
    @ResponseBody
    public InterfaceReponse indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
        logger.error("抛出 IndexOutOfBoundsException 异常：" + ex + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), ex);
        return InterfaceReponse.returnError("数组出界异常，异常类为：" + ex.getClass().getSimpleName(), ExceptionConstant.IndexOutOfBounds, ExceptionConstant.ERROR);

    }


    /**
     * 404异常处理
     */
    @ExceptionHandler(value = NoHandlerFoundException.class)
    @ResponseBody
    public InterfaceReponse errorHandler(HttpServletRequest request, NoHandlerFoundException exception, HttpServletResponse response) {
        logger.error("抛出NoHandlerFoundException异常：" + exception.getClass().getSimpleName() + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), exception);
        return InterfaceReponse.returnError("404异常，异常类为：" + exception.getClass().getSimpleName(), ExceptionConstant.other, ExceptionConstant.ERROR);
    }

    /**
     * 405异常处理
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public InterfaceReponse errorHandler(HttpServletRequest request, HttpRequestMethodNotSupportedException exception, HttpServletResponse response) {
        logger.error("抛出HttpRequestMethodNotSupportedException异常：" + exception.getClass().getSimpleName() + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), exception);
        return InterfaceReponse.returnError("405异常，异常类为：" + exception.getClass().getSimpleName(), ExceptionConstant.HttpRequestMethodNotSupported, ExceptionConstant.ERROR);
    }

    /**
     * 415异常处理
     */
    @ExceptionHandler(value = HttpMediaTypeNotSupportedException.class)
    @ResponseBody
    public InterfaceReponse errorHandler(HttpServletRequest request, HttpMediaTypeNotSupportedException exception, HttpServletResponse response) {
        logger.error("抛出HttpMediaTypeNotSupportedException异常：" + exception.getClass().getSimpleName() + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), exception);
        return InterfaceReponse.returnError("415异常，异常类为：" + exception.getClass().getSimpleName(), ExceptionConstant.HttpMediaTypeNotAcceptable, ExceptionConstant.ERROR);
    }


    /**
     * @param ex
     * @return
     * @Description 400 异常
     */

    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    @ResponseBody
    public InterfaceReponse httpMessageNotReadableExceptionHandler(HttpMessageNotReadableException ex) {
        logger.error("抛出HttpMessageNotReadableException 异常：" + ex + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), ex);
        return InterfaceReponse.returnError("400异常，异常类为：" + ex.getClass().getSimpleName(), ExceptionConstant.HttpMessageNotReadable, ExceptionConstant.ERROR);
    }


    /**
     * @Description 400 异常
     * @param ex
     * @return
     */
/*
    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    @ResponseBody
    public InterfaceReponse requestTypeMismatch(HttpMessageNotReadableException ex) {
        logger.error("抛出 HttpMessageNotReadableException 异常：" +ex + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond));
        return InterfaceReponse.returnError("400异常，异常类为："+ex.getClass().getSimpleName(),ExceptionConstant.HttpMessageNotReadable,ExceptionConstant.ERROR);
    }
*/


    /**
     * @param ex
     * @return
     * @Description 400 异常
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    @ResponseBody
    public InterfaceReponse requestMissingServletRequest(MissingServletRequestParameterException ex) {
        logger.error("抛出 MissingServletRequestParameterException 异常：" + ex + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), ex);
        return InterfaceReponse.returnError("400异常，异常类为：" + ex.getClass().getSimpleName(), ExceptionConstant.MissingServletRequestParameter, ExceptionConstant.ERROR);
    }


    @ExceptionHandler(value = EmptyResultDataAccessException.class)
    @ResponseBody
    public InterfaceReponse emptyResultDataAccessExceptioneHandler(EmptyResultDataAccessException ex) {
        logger.error("抛出 EmptyResultDataAccessException 异常：" + ex + ",时间为：" + DateUtils.getCurrentDate(DateUtils.formatSecond), ex);
        return InterfaceReponse.returnError("业务异常，查询结果为NULL", ExceptionConstant.BussinessException, ExceptionConstant.EXCEPTION);
    }


    /**
     * 对返回数据集中处理
     *
     * @param code
     * @param msg
     * @param ex
     * @param <T>
     * @return
     */
/*
    private <T extends Throwable> RestResponse resultOut(int code, String msg, T ex) {
        ex.printStackTrace();
        log.error(String.format(logExceptionFormat, code, ex.getMessage()));
        return RestResponse.fail(code).msg(msg);
    }
*/


}
